home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / HENSA / MATHS / PLPLOT / PLPLOT.ZIP / src / plctrl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-21  |  33.3 KB  |  1,319 lines

  1. /* $Id: plctrl.c,v 1.26 1994/09/02 05:09:42 mjl Exp $
  2.  * $Log: plctrl.c,v $
  3.  * Revision 1.26  1994/09/02  05:09:42  mjl
  4.  * Flush stdout before issuing error message, to be sure we are really on the
  5.  * text screen.
  6.  *
  7.  * Revision 1.25  1994/08/25  04:08:09  mjl
  8.  * Fixed limiting saturation value in a case that was affecting grayscale
  9.  * output.  Contributed by Radey Shouman.  Also modified pltext/plgra to
  10.  * return silently if plinit not yet called.
  11.  *
  12.  * Revision 1.24  1994/08/10  01:13:57  mjl
  13.  * Fixed hardwired DOS/GNUSVGA directory location.
  14.  *
  15.  * Revision 1.23  1994/07/29  20:23:53  mjl
  16.  * Added new function plLibOpen(), used for opening and returning the file
  17.  * handle for "library" files -- font files, map files, etc.  These are all
  18.  * located by the same search path.
  19.  *
  20.  * Revision 1.22  1994/07/26  21:14:41  mjl
  21.  * Improvements to the way PLplot looks for various files.  Now more
  22.  * consistent and flexible.  In particular, environmentals can be set for
  23.  * locations of each directory (for Tcl, binary, and library files).
  24.  * Contributed by Mark Olesen.
  25.  *
  26.  * Revision 1.21  1994/07/25  06:44:31  mjl
  27.  * Wrapped the include of unistd.h in a HAVE_UNISTD_H.
  28.  *
  29.  * Revision 1.20  1994/06/30  18:22:03  mjl
  30.  * All core source files: made another pass to eliminate warnings when using
  31.  * gcc -Wall.  Lots of cleaning up: got rid of includes of math.h or string.h
  32.  * (now included by plplot.h), and other minor changes.  Now each file has
  33.  * global access to the plstream pointer via extern; many accessor functions
  34.  * eliminated as a result.
  35. */
  36.  
  37. /*    plctrl.c
  38.  
  39.     Misc. control routines, like begin, end, exit, change graphics/text
  40.     mode, change color.  Includes some spillage from plcore.c.  If you
  41.     don't know where it should go, put it here.  
  42. */
  43.  
  44. #include "plplotP.h"
  45.  
  46. #ifdef __GO32__            /* dos386/djgpp */
  47. #ifdef __unix
  48. #undef __unix
  49. #endif
  50. #endif
  51.  
  52. #ifdef __unix
  53. #include <sys/types.h>
  54. #include <sys/stat.h>
  55. #ifdef HAVE_UNISTD_H
  56. #include <unistd.h>
  57. #endif
  58. #include <errno.h>
  59. #endif
  60.  
  61. /* Static functions */
  62.  
  63. static void
  64. strcat_delim(char *dirspec);
  65.  
  66. static int
  67. (*exit_handler) (char *errormsg);
  68.  
  69. /* An additional hardwired location for lib files. */
  70. /* I have no plans to change these again, ever. */
  71.  
  72. #if defined(AMIGA)
  73. #ifndef PLLIBDEV
  74. #define PLLIBDEV  "plplot:lib"
  75. #endif
  76.  
  77. #elif defined(GNU386)
  78. #ifndef PLLIBDEV
  79. #define PLLIBDEV "c:/plplot/lib"
  80. #endif
  81.  
  82. #elif defined(MSDOS)
  83. #ifndef PLLIBDEV
  84. #define PLLIBDEV "c:\\plplot\\lib"
  85. #endif
  86.  
  87. #elif defined (__riscos)
  88. #ifndef PLLIBDEV
  89. #define PLLIBDEV "$.plplot.lib"
  90. #endif
  91.  
  92. #else
  93.  
  94. /* Anything else is assumed to be Unix */
  95.  
  96. #ifndef PLLIBDEV
  97. #define PLLIBDEV "/usr/local/plplot/lib"
  98. #endif
  99.  
  100. #endif
  101.  
  102. /*----------------------------------------------------------------------*\
  103.  *  Routines that deal with colors & color maps.
  104. \*----------------------------------------------------------------------*/
  105.  
  106. /*----------------------------------------------------------------------*\
  107.  * plcol0()
  108.  *
  109.  * Set color, map 0.  Argument is integer between 0 and 15.
  110. \*----------------------------------------------------------------------*/
  111.  
  112. void
  113. c_plcol0(PLINT icol0)
  114. {
  115.     if (plsc->level < 1) {
  116.     plabort("plcol0: Please call plinit first");
  117.     return;
  118.     }
  119.     if (icol0 < 0 || icol0 > 15) {
  120.     plabort("plcol0: Invalid color.");
  121.     return;
  122.     }
  123.     if (plsc->cmap0setcol[icol0] == 0) {
  124.     plabort("plcol0: Requested color not allocated.");
  125.     return;
  126.     }
  127.  
  128.     plsc->icol0 = icol0;
  129.     plsc->curcolor.r = plsc->cmap0[icol0].r;
  130.     plsc->curcolor.g = plsc->cmap0[icol0].g;
  131.     plsc->curcolor.b = plsc->cmap0[icol0].b;
  132.  
  133.     plsc->curcmap = 0;
  134.     plP_state(PLSTATE_COLOR0);
  135. }
  136.  
  137. /*----------------------------------------------------------------------*\
  138.  * plcol1()
  139.  *
  140.  * Set color, map 1.  Argument is a float between 0. and 1.
  141. \*----------------------------------------------------------------------*/
  142.  
  143. void
  144. c_plcol1(PLFLT col1)
  145. {
  146.     PLINT icol1;
  147.  
  148.     if (plsc->level < 1) {
  149.     plabort("plcol1: Please call plinit first");
  150.     return;
  151.     }
  152.     if (col1 < 0 || col1 > 1) {
  153.     plabort("plcol1: Invalid color.");
  154.     return;
  155.     }
  156.  
  157.     icol1 = col1 * plsc->ncol1;
  158.     icol1 = MIN(icol1, plsc->ncol1-1);
  159.  
  160.     plsc->icol1 = icol1;
  161.     plsc->curcolor.r = plsc->cmap1[plsc->icol1].r;
  162.     plsc->curcolor.g = plsc->cmap1[plsc->icol1].g;
  163.     plsc->curcolor.b = plsc->cmap1[plsc->icol1].b;
  164.  
  165.     plsc->curcmap = 1;
  166.     plP_state(PLSTATE_COLOR1);
  167. }
  168.  
  169. /*----------------------------------------------------------------------*\
  170.  * plscolbg()
  171.  *
  172.  * Set the background color (cmap0[0]) by 8 bit RGB value
  173. \*----------------------------------------------------------------------*/
  174.  
  175. void
  176. c_plscolbg(PLINT r, PLINT g, PLINT b)
  177. {
  178.     plscol0(0, r, g, b);
  179. }
  180.  
  181. /*----------------------------------------------------------------------*\
  182.  * plgcolbg()
  183.  *
  184.  * Returns the background color (cmap0[0]) by 8 bit RGB value
  185. \*----------------------------------------------------------------------*/
  186.  
  187. void
  188. c_plgcolbg(PLINT *r, PLINT *g, PLINT *b)
  189. {
  190.     plgcol0(0, r, g, b);
  191. }
  192.  
  193. /*----------------------------------------------------------------------*\
  194.  * plscol0()
  195.  *
  196.  * Set a given color from color map 0 by 8 bit RGB value
  197.  * Does not result in any additional cells to be allocated.
  198. \*----------------------------------------------------------------------*/
  199.  
  200. void
  201. c_plscol0(PLINT icol0, PLINT r, PLINT g, PLINT b)
  202. {
  203.     if (icol0 < 0 || icol0 > 15) {
  204.     plabort("plscol0: Illegal color table value");
  205.     return;
  206.     }
  207.     if ((r < 0 || r > 255) || (g < 0 || g > 255) || (b < 0 || b > 255)) {
  208.     plabort("plscol0: Invalid color");
  209.     return;
  210.     }
  211.  
  212.     plsc->cmap0[icol0].r = r;
  213.     plsc->cmap0[icol0].g = g;
  214.     plsc->cmap0[icol0].b = b;
  215.     plsc->cmap0setcol[icol0] = 1;
  216.  
  217.     if (plsc->level > 0)
  218.     plP_state(PLSTATE_CMAP0);
  219. }
  220.  
  221. /*----------------------------------------------------------------------*\
  222.  * plgcol0()
  223.  *
  224.  * Returns 8 bit RGB values for given color from color map 0
  225.  * Values are negative if an invalid color id is given
  226. \*----------------------------------------------------------------------*/
  227.  
  228. void
  229. c_plgcol0(PLINT icol0, PLINT *r, PLINT *g, PLINT *b)
  230. {
  231.     *r = -1;
  232.     *g = -1;
  233.     *b = -1;
  234.  
  235.     if (icol0 < 0 || icol0 > 15) {
  236.     plabort("plgcol0: Invalid color index");
  237.     return;
  238.     }
  239.     if (plsc->cmap0setcol[icol0] == 0) {
  240.     plabort("plgcol0: Requested color not allocated");
  241.     return;
  242.     }
  243.  
  244.     *r = plsc->cmap0[icol0].r;
  245.     *g = plsc->cmap0[icol0].g;
  246.     *b = plsc->cmap0[icol0].b;
  247.  
  248.     return;
  249. }
  250.  
  251. /*----------------------------------------------------------------------*\
  252.  * plscmap0n()
  253.  *
  254.  * Set number of colors in cmap 0
  255.  * Must be <= 16, and the driver is not guaranteed to support all of these.
  256. \*----------------------------------------------------------------------*/
  257.  
  258. void
  259. c_plscmap0n(PLINT ncol0)
  260. {
  261.     if (ncol0 > 16 || ncol0 < 1) {
  262.     plabort("plscmap0n: Number of colors must be between 1 and 16");
  263.     return;
  264.     }
  265.  
  266.     plsc->ncol0 = ncol0;
  267. }
  268.  
  269. /*----------------------------------------------------------------------*\
  270.  * plscmap1n()
  271.  *
  272.  * Set number of colors in cmap 1
  273.  * Note that the driver is allowed to disregard this number.
  274.  * In particular, most use far fewer.
  275. \*----------------------------------------------------------------------*/
  276.  
  277. void
  278. c_plscmap1n(PLINT ncol1)
  279. {
  280.     if (ncol1 > 256 || ncol1 < 1) {
  281.     plabort("plscmap1n: Number of colors must be between 1 and 256");
  282.     return;
  283.     }
  284.  
  285.     plsc->ncol1 = ncol1;
  286. }
  287.  
  288. /*----------------------------------------------------------------------*\
  289.  * plscmap0()
  290.  *
  291.  * Set color map 0 colors by 8 bit RGB values
  292.  * This also sets the number of colors.
  293. \*----------------------------------------------------------------------*/
  294.  
  295. void
  296. c_plscmap0(PLINT *r, PLINT *g, PLINT *b, PLINT ncol0)
  297. {
  298.     int i;
  299.  
  300.     if (ncol0 > 16 || ncol0 < 1) {
  301.     plabort("plscmap0n: Number of colors must be between 1 and 16");
  302.     return;
  303.     }
  304.     plsc->ncol0 = ncol0;
  305.  
  306.     for (i = 0; i < plsc->ncol0; i++) {
  307.     if ((r[i] < 0 || r[i] > 255) ||
  308.         (g[i] < 0 || g[i] > 255) ||
  309.         (b[i] < 0 || b[i] > 255)) {
  310.  
  311.         fprintf(stderr, "plscmap0: Invalid RGB color: %d, %d, %d\n",
  312.             (int) r[i], (int) g[i], (int) b[i]);
  313.  
  314.         plabort("plscmap0: Invalid color");
  315.         return;
  316.     }
  317.  
  318.     plsc->cmap0[i].r = r[i];
  319.     plsc->cmap0[i].g = g[i];
  320.     plsc->cmap0[i].b = b[i];
  321.     plsc->cmap0setcol[i] = 1;
  322.     }
  323.  
  324.     if (plsc->level > 0)
  325.     plP_state(PLSTATE_CMAP0);
  326. }
  327.  
  328. /*----------------------------------------------------------------------*\
  329.  * plscmap1()
  330.  *
  331.  * Set color map 1 colors by 8 bit RGB values
  332.  * This also sets the number of colors.
  333. \*----------------------------------------------------------------------*/
  334.  
  335. void
  336. c_plscmap1(PLINT *r, PLINT *g, PLINT *b, PLINT ncol1)
  337. {
  338.     int i;
  339.  
  340.     if (ncol1 > 256 || ncol1 < 1) {
  341.     plabort("plscmap1n: Number of colors must be between 1 and 256");
  342.     return;
  343.     }
  344.  
  345.     plsc->ncol1 = ncol1;
  346.  
  347.     for (i = 0; i < plsc->ncol1; i++) {
  348.     if ((r[i] < 0 || r[i] > 255) ||
  349.         (g[i] < 0 || g[i] > 255) ||
  350.         (b[i] < 0 || b[i] > 255)) {
  351.  
  352.         fprintf(stderr, "plscmap1: Invalid RGB color: %d, %d, %d\n",
  353.             (int) r[i], (int) g[i], (int) b[i]);
  354.  
  355.         plabort("plscmap1: Invalid color");
  356.         return;
  357.     }
  358.     plsc->cmap1[i].r = r[i];
  359.     plsc->cmap1[i].g = g[i];
  360.     plsc->cmap1[i].b = b[i];
  361.     }
  362.  
  363.     plsc->cmap1set = 1;
  364.     if (plsc->level > 0)
  365.     plP_state(PLSTATE_CMAP1);
  366. }
  367.  
  368. /*----------------------------------------------------------------------*\
  369.  * plscmap1l()
  370.  *
  371.  * Set color map 1 colors using a piece-wise linear relationship between
  372.  * position in the color map (from 0 to 1) and position in HLS or RGB color
  373.  * space.  May be called at any time.
  374.  *
  375.  * The idea here is to specify a number of control points that specify the
  376.  * mapping between HLS (or RGB or CMY) and palette 1 value.  Between these
  377.  * points, linear interpolation is used.  By mapping position in the color
  378.  * map to function value, this gives a smooth variation of color with
  379.  * intensity.  Any number of control points may be specified, located at
  380.  * arbitrary positions (intensities), although typically 2 - 4 are enough.
  381.  * Another way of stating this is that we are traversing a given number of
  382.  * lines through HLS (or RGB) space as we move through cmap 1 entries.  The
  383.  * control points at the minimum and maximum intensity (0 and 1) must
  384.  * always be specified.  By adding more control points you can get more
  385.  * variation.  One good technique for plotting functions that vary about
  386.  * some expected average is to use an additional 2 control points in the
  387.  * center (intensity ~= 0.5) that are the same color as the background
  388.  * (typically white for paper output, black for crt), and same hue as the
  389.  * boundary control points.  This allows the highs and lows to be very
  390.  * easily distinguished.
  391.  *
  392.  * Each control point must specify the position in cmap 1 as well as
  393.  * three coordinates in HLS or RGB space.  The first point MUST correspond
  394.  * to position = 0, and the last to position = 1.
  395.  *
  396.  * Bounds on RGB coordinates:
  397.  *    R,G,B        [0, 1]        magnitude
  398.  *
  399.  * Bounds on HLS coordinates:
  400.  *    hue        [0, 360]    degrees
  401.  *    lightness    [0, 1]        magnitude
  402.  *    saturation    [0, 1]        magnitude
  403.  *
  404.  * The inputs are:
  405.  *    itype        0: HLS, 1: RGB
  406.  *    npts        number of control points
  407.  *    pos[]        position for each control point
  408.  *    coord1[]    first coordinate for each control point
  409.  *    coord2[]    second coordinate for each control point
  410.  *    coord3[]    third coordinate for each control point 
  411. \*----------------------------------------------------------------------*/
  412.  
  413. void
  414. c_plscmap1l(PLINT itype, PLINT npts, PLFLT *pos,
  415.         PLFLT *coord1, PLFLT *coord2, PLFLT *coord3)
  416. {
  417.     int n;
  418.     PLFLT h, l, s, r, g, b;
  419.  
  420.     if (npts < 2) {
  421.     plabort("plscmap1l: Must specify at least two control points");
  422.     return;
  423.     }
  424.  
  425.     if ( (pos[0] != 0) || (pos[npts-1] != 1)) {
  426.     plabort("plscmap1l: First, last control points must lie on boundary");
  427.     return;
  428.     }
  429.  
  430.     if ( npts > 32 ) {
  431.     plabort("plscmap1l: Maximum of 32 control points allowed");
  432.     return;
  433.     }
  434.  
  435.     if (plsc->ncol1 == 0)
  436.     plsc->ncol1 = 256;
  437.  
  438. /* Save control points */
  439.  
  440.     plsc->ncp1 = npts;
  441.  
  442.     for (n = 0; n < npts; n++) {
  443.  
  444.     if (itype == 0) {
  445.         h = coord1[n];
  446.         l = coord2[n];
  447.         s = coord3[n];
  448.     }
  449.     else {
  450.         r = coord1[n];
  451.         g = coord2[n];
  452.         b = coord3[n];
  453.         plRGB_HLS(r, g, b, &h, &l, &s);
  454.     }
  455.  
  456.     plsc->cmap1cp[n].h = h;
  457.     plsc->cmap1cp[n].l = l;
  458.     plsc->cmap1cp[n].s = s;
  459.     plsc->cmap1cp[n].p = pos[n];
  460.     }
  461.  
  462. /* Calculate and set color map */
  463.  
  464.     plcmap1_calc();
  465. }
  466.  
  467. /*----------------------------------------------------------------------*\
  468.  * plcmap1_calc()
  469.  *
  470.  * Bin up cmap 1 space and assign colors to make inverse mapping easy.
  471.  * Always do interpolation in HLS space.
  472. \*----------------------------------------------------------------------*/
  473.  
  474. void
  475. plcmap1_calc(void)
  476. {
  477.     int i, n;
  478.     PLFLT icmap1, delta;
  479.     PLFLT h, l, s, r, g, b;
  480.  
  481.     for (n = 0; n < plsc->ncp1-1; n++) {
  482.  
  483.     if ( plsc->cmap1cp[n].p == plsc->cmap1cp[n+1].p )
  484.         continue;
  485.  
  486.     for (i = 0; i < plsc->ncol1; i++) {
  487.         icmap1 = (double) i / (plsc->ncol1 - 1.0);
  488.         if ( (icmap1 < plsc->cmap1cp[n].p) ||
  489.          (icmap1 > plsc->cmap1cp[n+1].p) )
  490.         continue;
  491.  
  492.         delta = (icmap1 - plsc->cmap1cp[n].p) /
  493.         (plsc->cmap1cp[n+1].p - plsc->cmap1cp[n].p);
  494.  
  495.         h = plsc->cmap1cp[n].h +
  496.         (plsc->cmap1cp[n+1].h - plsc->cmap1cp[n].h) * delta;
  497.         l = plsc->cmap1cp[n].l +
  498.         (plsc->cmap1cp[n+1].l - plsc->cmap1cp[n].l) * delta;
  499.         s = plsc->cmap1cp[n].s +
  500.         (plsc->cmap1cp[n+1].s - plsc->cmap1cp[n].s) * delta;
  501.  
  502.         plHLS_RGB(h, l, s, &r, &g, &b);
  503.  
  504.         plsc->cmap1[i].r = MAX(0, MIN(255, (int) (256. * r)));
  505.         plsc->cmap1[i].g = MAX(0, MIN(255, (int) (256. * g)));
  506.         plsc->cmap1[i].b = MAX(0, MIN(255, (int) (256. * b)));
  507.     }
  508.     }
  509.  
  510.     plsc->cmap1set = 1;
  511.     if (plsc->level > 0)
  512.     plP_state(PLSTATE_CMAP1);
  513. }
  514.  
  515. /*----------------------------------------------------------------------*\
  516.  * color_def()
  517.  *
  518.  * Initializes color table entries by RGB values.
  519.  * Does nothing if color already set.
  520. \*----------------------------------------------------------------------*/
  521.  
  522. static void
  523. color_def(PLINT i, U_CHAR r, U_CHAR g, U_CHAR b)
  524. {
  525.     if ( ! plsc->cmap0setcol[i] && i < plsc->ncol0) {
  526.     plsc->cmap0[i].r = r;
  527.     plsc->cmap0[i].g = g;
  528.     plsc->cmap0[i].b = b;
  529.     plsc->cmap0setcol[i] = 1;
  530.     }
  531. }
  532.  
  533. /*----------------------------------------------------------------------*\
  534.  * plCmap0_init()
  535.  *
  536.  * Initializes color map 0.
  537.  * Do not initialize if already done.
  538.  *
  539.  * Initial RGB values for color map 0 taken from HPUX 8.07 X-windows 
  540.  * rgb.txt file, and may not accurately represent the described colors on 
  541.  * all systems.
  542.  *
  543.  * Note the background color is not set, since the device driver may be
  544.  * able to detect if a monochrome output device is being used, in which
  545.  * case I want to choose the default background color there.
  546. \*----------------------------------------------------------------------*/
  547.  
  548. void
  549. plCmap0_init(void)
  550. {
  551.     if (plsc->ncol0 == 0)
  552.     plsc->ncol0 = 16;
  553.  
  554. /* Color map 0 */
  555. /* Any entries already filled by user or unallocated are not touched */
  556.  
  557.     color_def(0,    0,   0,   0);    /* black */
  558.     color_def(1,  255,   0,   0);    /* red */
  559.     color_def(2,  255, 255,   0);    /* yellow */
  560.     color_def(3,    0, 255,   0);    /* green */
  561.     color_def(4,   50, 191, 193);    /* aquamarine */
  562.     color_def(5,  255, 181, 197);    /* pink */
  563.     color_def(6,  245, 222, 179);    /* wheat */
  564.     color_def(7,  126, 126, 126);    /* grey */
  565.     color_def(8,  165,  42,  42);    /* brown */
  566.     color_def(9,    0,   0, 255);    /* blue */
  567.     color_def(10, 138,  43, 226);    /* Blue Violet */
  568.     color_def(11,   0, 255, 255);    /* cyan */
  569.     color_def(12,  25, 204, 223);    /* turquoise */
  570.     color_def(13, 255,   0, 255);    /* magenta */
  571.     color_def(14, 233, 150, 122);    /* salmon */
  572.     color_def(15, 255, 255, 255);    /* white */
  573. }
  574.  
  575. /*----------------------------------------------------------------------*\
  576.  * plCmap1_init()
  577.  *
  578.  * Initializes color map 1.
  579.  * Do not initialize if already done.
  580.  *
  581.  * The default initialization uses 4 control points in HLS space, the two
  582.  * inner ones being very close to one of the vertices of the HLS double
  583.  * cone.  The vertex used (black or white) is chosen to be the closer to
  584.  * the background color.  If you don't like these settings you can always
  585.  * initialize it yourself.
  586. \*----------------------------------------------------------------------*/
  587.  
  588. void
  589. plCmap1_init(void)
  590. {
  591.     PLFLT i[4], h[4], l[4], s[4], vertex;
  592.  
  593. /* Return if the user has already filled color map */
  594.  
  595.     if (plsc->cmap1set)
  596.     return;
  597.  
  598. /* Positions of control points */
  599.  
  600.     i[0] = 0;        /* left boundary */
  601.     i[1] = 0.45;    /* just before center */
  602.     i[2] = 0.55;    /* just after center */
  603.     i[3] = 1;        /* right boundary */
  604.  
  605. /* For center control points, pick black or white, whichever is closer to bg */
  606. /* Be carefult to pick just short of top or bottom else hue info is lost */
  607.  
  608.     vertex = ((float) plsc->cmap0[0].r + (float) plsc->cmap0[0].g +
  609.           (float) plsc->cmap0[0].b) / 3. / 255.;
  610.  
  611.     if (vertex < 0.5)
  612.     vertex = 0.01;
  613.     else
  614.     vertex = 0.99;
  615.  
  616. /* Set hue */
  617.  
  618.     h[0] = 260;        /* low: blue-violet */
  619.     h[1] = 260;        /* only change as we go over vertex */
  620.     h[2] = 0;        /* high: red */
  621.     h[3] = 0;        /* keep fixed */
  622.  
  623. /* Set lightness */
  624.  
  625.     l[0] = 0.5;        /* low */
  626.     l[1] = vertex;    /* bg */
  627.     l[2] = vertex;    /* bg */
  628.     l[3] = 0.5;        /* high */
  629.  
  630. /* Set saturation -- keep at maximum */
  631.  
  632.     s[0] = 1;
  633.     s[1] = 1;
  634.     s[2] = 1;
  635.     s[3] = 1;
  636.  
  637.     c_plscmap1l(0, 4, i, h, l, s);
  638. }
  639.  
  640. /*----------------------------------------------------------------------*\
  641.  * plscolor()
  642.  *
  643.  * Used to globally turn color output on/off
  644. \*----------------------------------------------------------------------*/
  645.  
  646. void
  647. c_plscolor(PLINT color)
  648. {
  649.     plsc->colorset = 1;
  650.     plsc->color = color;
  651. }
  652.  
  653. /*----------------------------------------------------------------------*\
  654.  * plrgb()
  655.  *
  656.  * Set line color by red, green, blue from  0. to 1.
  657.  * Do NOT use this.  Only retained for backward compatibility
  658. \*----------------------------------------------------------------------*/
  659.  
  660. void
  661. c_plrgb(PLFLT r, PLFLT g, PLFLT b)
  662. {
  663.     if (plsc->level < 1) {
  664.     plabort("plrgb: Please call plinit first");
  665.     return;
  666.     }
  667.  
  668.     plsc->icol0 = PL_RGB_COLOR;
  669.     plsc->curcolor.r = MAX(0, MIN(255, (int) (256. * r)));
  670.     plsc->curcolor.g = MAX(0, MIN(255, (int) (256. * g)));
  671.     plsc->curcolor.b = MAX(0, MIN(255, (int) (256. * b)));
  672.  
  673.     plsc->curcmap = 0;
  674.     plP_state(PLSTATE_COLOR0);
  675. }
  676.  
  677. /*----------------------------------------------------------------------*\
  678.  * plrgb1()
  679.  *
  680.  * Set line color by 8 bit RGB values.
  681.  * See note to plrgb()
  682. \*----------------------------------------------------------------------*/
  683.  
  684. void
  685. c_plrgb1(PLINT r, PLINT g, PLINT b)
  686. {
  687.     if (plsc->level < 1) {
  688.     plabort("plrgb1: Please call plinit first");
  689.     return;
  690.     }
  691.     if ((r < 0 || r > 255) || (g < 0 || g > 255) || (b < 0 || b > 255)) {
  692.     plabort("plrgb1: Invalid color");
  693.     return;
  694.     }
  695.  
  696.     plsc->icol0 = PL_RGB_COLOR;
  697.     plsc->curcolor.r = r;
  698.     plsc->curcolor.g = g;
  699.     plsc->curcolor.b = b;
  700.  
  701.     plsc->curcmap = 0;
  702.     plP_state(PLSTATE_COLOR0);
  703. }
  704.  
  705. /*----------------------------------------------------------------------*\
  706.  * void plhls()
  707.  *
  708.  * Set current color by hue, lightness, and saturation.
  709.  * Convert hls color coordinates to rgb, then call plrgb.
  710.  * See note to plrgb()
  711. \*----------------------------------------------------------------------*/
  712.  
  713. void
  714. c_plhls(PLFLT h, PLFLT l, PLFLT s)
  715. {
  716.     PLFLT r, g, b;
  717.  
  718.     plHLS_RGB(h, l, s, &r, &g, &b);
  719.     plrgb(r, g, b);
  720. }
  721.  
  722. /*----------------------------------------------------------------------*\
  723.  * void value()
  724.  *
  725.  * Auxiliary function used by plHLS_RGB().
  726. \*----------------------------------------------------------------------*/
  727.  
  728. static float
  729. value(double n1, double n2, double hue)
  730. {
  731.     float val;
  732.  
  733.     while (hue >= 360.)
  734.     hue -= 360.;
  735.     while (hue < 0.)
  736.     hue += 360.;
  737.  
  738.     if (hue < 60.)
  739.     val = n1 + (n2 - n1) * hue / 60.;
  740.     else if (hue < 180.)
  741.     val = n2;
  742.     else if (hue < 240.)
  743.     val = n1 + (n2 - n1) * (240. - hue) / 60.;
  744.     else
  745.     val = n1;
  746.  
  747.     return (val);
  748. }
  749.  
  750. /*----------------------------------------------------------------------*\
  751.  * void plHLS_RGB()
  752.  *
  753.  * Convert HLS color to RGB color.
  754.  * Bounds on HLS (input):
  755.  *    hue        [0., 360.]    degrees
  756.  *    lightness    [0., 1.]    magnitude
  757.  *    saturation    [0., 1.]    magnitude
  758.  *
  759.  * Hue is always mapped onto the interval [0., 360.] regardless of input.
  760.  * Bounds on RGB (output) is always [0., 1.].  Convert to RGB color values
  761.  * by multiplying by 2**nbits (nbits typically 8).
  762. \*----------------------------------------------------------------------*/
  763.  
  764. void
  765. plHLS_RGB(PLFLT h, PLFLT l, PLFLT s, PLFLT *p_r, PLFLT *p_g, PLFLT *p_b)
  766. {
  767.     float m1, m2;
  768.  
  769.     if (l <= .5)
  770.     m2 = l * (s + 1.);
  771.     else
  772.     m2 = l + s - l * s;
  773.  
  774.     m1 = 2 * l - m2;
  775.  
  776.     *p_r = value(m1, m2, h + 120.);
  777.     *p_g = value(m1, m2, h);
  778.     *p_b = value(m1, m2, h - 120.);
  779. }
  780.  
  781. /*----------------------------------------------------------------------*\
  782.  * void plRGB_HLS()
  783.  *
  784.  * Convert RGB color to HLS color.
  785.  * Bounds on RGB (input) is always [0., 1.].  
  786.  * Bounds on HLS (output):
  787.  *    hue        [0., 360.]    degrees
  788.  *    lightness    [0., 1.]    magnitude
  789.  *    saturation    [0., 1.]    magnitude
  790. \*----------------------------------------------------------------------*/
  791.  
  792. void
  793. plRGB_HLS(PLFLT r, PLFLT g, PLFLT b, PLFLT *p_h, PLFLT *p_l, PLFLT *p_s)
  794. {
  795.     PLFLT h, l, s, d, rc, gc, bc, rgb_min, rgb_max;
  796.  
  797.     rgb_min = MIN( r, MIN( g, b ));
  798.     rgb_max = MAX( r, MAX( g, b ));
  799.  
  800.     l = (rgb_min+rgb_max) / 2.0;
  801.  
  802.     if (rgb_min == rgb_max) {
  803.     s = 0;
  804.     h = 0;
  805.     } 
  806.     else {
  807.     d = rgb_max - rgb_min;
  808.     if (l < 0.5)
  809.         s = 0.5 * d / l;
  810.     else 
  811.         s = 0.5* d / (1.-l);
  812.  
  813.     rc = (rgb_max-r) / d;
  814.     gc = (rgb_max-g) / d;
  815.     bc = (rgb_max-b) / d;
  816.  
  817.     if (r == rgb_max)
  818.         h = bc-gc;
  819.     else if (g == rgb_max)
  820.         h = rc-bc+2;
  821.     else
  822.         h = gc-rc-2;
  823.  
  824.     h = h*60;
  825.     if (h <  0)
  826.         h = h+360;
  827.     else if (h >= 360)
  828.         h = h-360;
  829.     }
  830.     *p_h = h;
  831.     *p_l = l;
  832.     *p_s = s;
  833. }
  834.  
  835. /*----------------------------------------------------------------------*\
  836.  * A grab-bag of various control routines.
  837. \*----------------------------------------------------------------------*/
  838.  
  839. /*----------------------------------------------------------------------*\
  840.  * void plwarn()
  841.  *
  842.  * A handy way to issue warnings, if need be.
  843. \*----------------------------------------------------------------------*/
  844.  
  845. void
  846. plwarn(char *errormsg)
  847. {
  848.     int was_gfx = 0;
  849.  
  850.     if (plsc->graphx == 1) {
  851.     was_gfx = 1;
  852.     pltext();
  853.     }
  854.  
  855.     fprintf(stderr, "\n*** PLPLOT WARNING ***\n");
  856.     if (*errormsg != '\0')
  857.     fprintf(stderr, "%s\n", errormsg);
  858.  
  859.     if (was_gfx == 1)
  860.     plgra();
  861. }
  862.  
  863. /*----------------------------------------------------------------------*\
  864.  * void plabort()
  865.  *
  866.  * Exactly the same as plwarn(), but appends ", aborting operation" to the
  867.  * error message.  Helps to keep source code uncluttered and provides a
  868.  * convention for error aborts.
  869. \*----------------------------------------------------------------------*/
  870.  
  871. void
  872. plabort(char *errormsg)
  873. {
  874.     int was_gfx = 0;
  875.  
  876.     if (plsc->graphx == 1) {
  877.     was_gfx = 1;
  878.     pltext();
  879.     }
  880.  
  881.     fprintf(stderr, "\n*** PLPLOT WARNING ***\n");
  882.     if (*errormsg != '\0')
  883.     fprintf(stderr, "%s, aborting operation\n", errormsg);
  884.  
  885.     if (was_gfx == 1)
  886.     plgra();
  887. }
  888.  
  889. /*----------------------------------------------------------------------*\
  890.  * void plexit()
  891.  *
  892.  * In case of an abort this routine is called.  It just prints out an error
  893.  * message and tries to clean up as much as possible.  It's best to turn
  894.  * off pause and then restore previous setting before returning.
  895.  *
  896.  * If cleanup needs to be done in the main program, the user should write
  897.  * his/her own exit handler and pass it in via plsexit().  This function
  898.  * should should either call plend() before exiting, or simply return.
  899. \*----------------------------------------------------------------------*/
  900.  
  901. void
  902. plexit(char *errormsg)
  903. {
  904.     int status = 1;
  905.  
  906.     if (exit_handler != NULL)
  907.     status = (*exit_handler)(errormsg);
  908.  
  909.     plsc->nopause = 1;
  910.     plend();
  911.     if (*errormsg != '\0') {
  912.     fprintf(stderr, "\n*** PLPLOT ERROR ***\n");
  913.     fprintf(stderr, "%s\n", errormsg);
  914.     }
  915.  
  916.     fprintf(stderr, "Program aborted\n");
  917.     exit(status);
  918. }
  919.  
  920. /*----------------------------------------------------------------------*\
  921.  * void plsexit()
  922.  *
  923.  * Sets an optional user exit handler.
  924. \*----------------------------------------------------------------------*/
  925.  
  926. void
  927. plsexit(int (*handler) (char *))
  928. {
  929.     exit_handler = handler;
  930. }
  931.  
  932. /*----------------------------------------------------------------------*\
  933.  * void plgra()
  934.  *
  935.  * Switches to graphics screen.  
  936.  *
  937.  * Here and in pltext() it's a good idea to return silently if plinit()
  938.  * hasn't yet been called, since plwarn() calls pltext() and plgra(), and
  939.  * plwarn() may be called at any time.
  940. \*----------------------------------------------------------------------*/
  941.  
  942. void
  943. c_plgra(void)
  944. {
  945.     if (plsc->level > 0)
  946.     plP_esc(PLESC_GRAPH, NULL);
  947. }
  948.  
  949. /*----------------------------------------------------------------------*\
  950.  * void pltext()
  951.  *
  952.  * Switches to text screen.
  953. \*----------------------------------------------------------------------*/
  954.  
  955. void
  956. c_pltext(void)
  957. {
  958.     if (plsc->level > 0) {
  959.     plP_esc(PLESC_TEXT, NULL);
  960.     plflush();
  961.     }
  962. }
  963.  
  964. /*----------------------------------------------------------------------*\
  965.  * void pl_cmd()
  966.  *
  967.  * Front-end to driver escape function.
  968.  * In principle this can be used to pass just about anything directly
  969.  * to the driver.
  970. \*----------------------------------------------------------------------*/
  971.  
  972. void
  973. pl_cmd(PLINT op, void *ptr)
  974. {
  975.     plP_esc(op, ptr);
  976. }
  977.  
  978. /*----------------------------------------------------------------------*\
  979.  * char *plFindCommand
  980.  *
  981.  * Looks for the specified executable file.  Search path:
  982.  *    PLPLOT_BIN_ENV = $(PLPLOT_BIN)
  983.  *    current directory
  984.  *    PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin
  985.  *    BIN_DIR
  986.  *
  987.  * The caller must free the returned pointer (points to malloc'ed memory)
  988.  * when finished with it.
  989. \*----------------------------------------------------------------------*/
  990.  
  991. char *
  992. plFindCommand(char *fn)
  993. {
  994.     char *fs = NULL, *dn;
  995.  
  996. /* PLPLOT_BIN_ENV = $(PLPLOT_BIN) */
  997.  
  998. #if defined(PLPLOT_BIN_ENV)
  999.     if ((dn = getenv(PLPLOT_BIN_ENV)) != NULL) {
  1000.         plGetName(dn, "", fn, &fs);
  1001.         if ( ! plFindName(fs))
  1002.             return fs;
  1003.         fprintf(stderr, PLPLOT_BIN_ENV"=\"%s\"\n", dn); /* what IS set? */
  1004.     }
  1005. #endif  /* PLPLOT_BIN_ENV */
  1006.  
  1007. /* Current directory */
  1008.  
  1009.     plGetName(".", "", fn, &fs);
  1010.     if ( ! plFindName(fs))
  1011.     return fs;
  1012.  
  1013. /* PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin */
  1014.  
  1015. #if defined(PLPLOT_HOME_ENV)
  1016.     if ((dn = getenv(PLPLOT_HOME_ENV)) != NULL) {
  1017.         plGetName(dn, "bin", fn, &fs);
  1018.         if ( ! plFindName(fs))
  1019.             return fs;
  1020.         fprintf(stderr, PLPLOT_HOME_ENV"=\"%s\"\n",dn); /* what IS set? */
  1021.     }
  1022. #endif  /* PLPLOT_HOME_ENV */
  1023.  
  1024. /* BIN_DIR */
  1025.  
  1026. #if defined (BIN_DIR)
  1027.     plGetName(BIN_DIR, "", fn, &fs);
  1028.     if ( ! plFindName(fs))
  1029.     return fs;
  1030. #endif
  1031.  
  1032. /* Crapped out */
  1033.  
  1034.     free_mem(fs);
  1035.     fprintf(stderr, "plFindCommand: cannot locate command: %s\n", fn);
  1036. #if defined (BIN_DIR)
  1037.     fprintf(stderr, "bin dir=\"" BIN_DIR "\"\n" );      /* what WAS set? */
  1038. #endif  /* BIN_DIR */
  1039.     return NULL;
  1040. }
  1041.  
  1042. /*----------------------------------------------------------------------*\
  1043.  * FILE *plLibOpen(fn)
  1044.  *
  1045.  * Return file pointer to lib file.
  1046.  * Locations checked:
  1047.  *    PLPLOT_LIB_ENV = $(PLPLOT_LIB)
  1048.  *    current directory
  1049.  *    PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib
  1050.  *    LIB_DIR
  1051.  *    PLLIBDEV
  1052. \*----------------------------------------------------------------------*/
  1053.  
  1054. FILE *
  1055. plLibOpen(char *fn)
  1056. {
  1057.     FILE *file;
  1058.     char *fs = NULL, *dn = NULL;
  1059.  
  1060. /****    search PLPLOT_LIB_ENV = $(PLPLOT_LIB)    ****/
  1061.  
  1062. #if defined(PLPLOT_LIB_ENV)
  1063.     if ((dn = getenv(PLPLOT_LIB_ENV)) != NULL) {
  1064.         plGetName(dn, "", fn, &fs);
  1065.  
  1066.         if ((file = fopen(fs, "rb")) != NULL)
  1067.             goto done;
  1068.  
  1069.         fprintf(stderr, PLPLOT_LIB_ENV"=\"%s\"\n", dn); /* what IS set? */
  1070.     }
  1071. #endif  /* PLPLOT_LIB_ENV */
  1072.  
  1073. /****    search current directory    ****/
  1074.  
  1075.     if ((file = fopen(fn, "rb")) != NULL)
  1076.         goto done;
  1077.  
  1078. /****    search PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib    ****/
  1079.  
  1080. #if defined (PLPLOT_HOME_ENV)
  1081.     if ((dn = getenv(PLPLOT_HOME_ENV)) != NULL) {
  1082.         plGetName(dn, "lib", fn, &fs);
  1083.  
  1084.         if ((file = fopen(fs, "rb")) != NULL)
  1085.             goto done;
  1086.         fprintf(stderr, PLPLOT_HOME_ENV"=\"%s\"\n",dn); /* what IS set? */
  1087.     }
  1088. #endif  /* PLPLOT_HOME_ENV/lib */
  1089.  
  1090. /****     search installed location    ****/
  1091.  
  1092. #if defined (LIB_DIR)
  1093.     plGetName(LIB_DIR, "", fn, &fs);
  1094.  
  1095.     if ((file = fopen(fs, "rb")) != NULL)
  1096.         goto done;
  1097. #endif  /* LIB_DIR */
  1098.  
  1099. /****     search hardwired location    ****/
  1100.  
  1101. #ifdef PLLIBDEV
  1102.     plGetName(PLLIBDEV, "", fn, &fs);
  1103.  
  1104.     if ((file = fopen(fs, "rb")) != NULL)
  1105.     goto done;
  1106. #endif    /* PLLIBDEV */
  1107.  
  1108. /****     not found, give up     ****/
  1109.  
  1110.     pltext();
  1111.     fprintf(stderr, "\nCannot open library file: %s\n", fn);
  1112. #if defined (LIB_DIR)
  1113.     fprintf(stderr, "lib dir=\"" LIB_DIR "\"\n" );      /* what WAS set? */
  1114. #endif  /* LIB_DIR */
  1115.     plgra();
  1116.     return NULL;
  1117.  
  1118.  done:
  1119.     free_mem(fs);
  1120.     return (file);
  1121. }
  1122.  
  1123. /*----------------------------------------------------------------------*\
  1124.  * int plFindName
  1125.  *
  1126.  * Authors: Paul Dubois (LLNL), others?
  1127.  * This function is in the public domain.
  1128.  *
  1129.  * Given a pathname, determine if it is a symbolic link.  If so, continue
  1130.  * searching to the ultimate terminus - there may be more than one link.
  1131.  * Use the error value to determine when the terminus is reached, and to
  1132.  * determine if the pathname really exists.  Then stat it to determine
  1133.  * whether it's executable.  Return 0 for an executable, errno otherwise.
  1134.  * Note that 'p' _must_ have at least one '/' character - it does by
  1135.  * construction in this program.  The contents of the array pointed to by
  1136.  * 'p' are changed to the actual pathname if findname is successful.
  1137.  *
  1138.  * This function is only defined under Unix for now.
  1139. \*----------------------------------------------------------------------*/
  1140.  
  1141. #ifdef __unix
  1142. int 
  1143. plFindName(char *p)
  1144. {
  1145.     int n;
  1146.     char buf[1024], *cp;
  1147.     extern int errno;
  1148.     struct stat sbuf;
  1149.  
  1150.     while ((n = readlink(p, buf, 1024)) > 0) {
  1151. #ifdef DEBUG
  1152.     fprintf(stderr, "Readlink read %d chars at: %s\n", n, p);
  1153. #endif
  1154.     if (buf[0] == '/') {    /* Link is an absolute path */
  1155.         strncpy(p, buf, n);
  1156.         p[n] = '\0';
  1157. #ifdef DEBUG
  1158.         fprintf(stderr, "Link is absolute: %s\n", p);
  1159. #endif
  1160.     }
  1161.     else {            /* Link is relative to its directory; make it
  1162.                    absolute */
  1163.         cp = 1 + strrchr(p, '/');
  1164.         strncpy(cp, buf, n);
  1165.         cp[n] = '\0';
  1166. #ifdef DEBUG
  1167.         fprintf(stderr, "Link is relative: %s\n\tTotal path: %s\n", cp, p);
  1168. #endif
  1169.     }
  1170.     }
  1171.  
  1172. /* SGI machines return ENXIO instead of EINVAL Dubois 11/92 */
  1173.  
  1174.     if (errno == EINVAL || errno == ENXIO) {
  1175. #ifdef DEBUG
  1176.     fprintf(stderr, "%s may be the one ...", p);
  1177. #endif
  1178. #ifdef SX
  1179. #define S_ISREG(mode)   (mode & S_IFREG)
  1180. #endif
  1181.     if ((stat(p, &sbuf) == 0) && S_ISREG(sbuf.st_mode)) {
  1182. #ifdef DEBUG
  1183.         fprintf(stderr, "regular file\n");
  1184. #endif
  1185.         return (access(p, X_OK));
  1186.     }
  1187.     }
  1188. #ifdef DEBUG
  1189.     fprintf(stderr, "not executable\n");
  1190. #endif
  1191.     return (errno ? errno : -1);
  1192. }
  1193.  
  1194. #else
  1195. int 
  1196. plFindName(char *p)
  1197. {
  1198.     return 1;
  1199. }
  1200. #endif
  1201.  
  1202. /*----------------------------------------------------------------------*\
  1203.  * void plGetName()
  1204.  *
  1205.  * Gets search name for file by concatenating the dir, subdir, and file
  1206.  * name, allocating memory as needed.  The appropriate delimiter is added
  1207.  * after the dir specification as necessary.  The caller is responsible
  1208.  * for freeing the malloc'ed memory.
  1209. \*----------------------------------------------------------------------*/
  1210.  
  1211. void
  1212. plGetName(char *dir, char *subdir, char *filename, char **filespec)
  1213. {
  1214.     int lfilespec;
  1215.  
  1216. /* Malloc space for filespec */
  1217.  
  1218.     free_mem(*filespec);
  1219.     lfilespec = 10;
  1220.     lfilespec = strlen(dir) + strlen(subdir) + strlen(filename) + 10;
  1221.     *filespec = (char *) malloc(lfilespec);
  1222.  
  1223.     strcpy(*filespec, dir);
  1224.  
  1225.     if (*subdir != '\0') {
  1226.     strcat_delim(*filespec);
  1227.     strcat(*filespec, subdir);
  1228.     }
  1229.     if (*filename != '\0') {
  1230.     strcat_delim(*filespec);
  1231.     strcat(*filespec, filename);
  1232.     }
  1233. }
  1234.  
  1235. /*----------------------------------------------------------------------*\
  1236.  * void strcat_delim()
  1237.  *
  1238.  * Append path name deliminator if necessary (does not add one if one's
  1239.  * there already, or if dealing with a colon-terminated device name as
  1240.  * used on the Amiga).
  1241. \*----------------------------------------------------------------------*/
  1242.  
  1243. static void
  1244. strcat_delim(char *dirspec)
  1245. {
  1246.     int ldirspec = strlen(dirspec);
  1247. #if defined (MSDOS)
  1248.     if (dirspec[ldirspec-1] != '\\')
  1249.     strcat(dirspec, "\\");
  1250. #elif defined (AMIGA)
  1251.     if (dirspec[ldirspec-1] != '/' && dirspec[ldirspec-1] != ':')
  1252.     strcat(dirspec, "/");
  1253. #elif defined (__riscos)
  1254.     if (dirspec[ldirspec-1] != '.')
  1255.     strcat(dirspec, "."); 
  1256. #else           /* unix is the default */
  1257.     if (dirspec[ldirspec-1] != '/')
  1258.     strcat(dirspec, "/");
  1259. #endif
  1260. }
  1261.  
  1262. /*----------------------------------------------------------------------*\
  1263.  * plGetInt()
  1264.  *
  1265.  * Prompts human to input an integer in response to given message.
  1266. \*----------------------------------------------------------------------*/
  1267.  
  1268. PLINT
  1269. plGetInt(char *s)
  1270. {
  1271.     int m;
  1272.     int i = 0;
  1273.     char line[256];
  1274.  
  1275.     while (i++ < 10) {
  1276.     fprintf(stdout, s);
  1277.     fgets(line, sizeof(line), stdin);
  1278. #ifdef MSDOS
  1279.     m = atoi(line);
  1280.     return (m);
  1281. #else
  1282.     if (sscanf(line, "%d", &m) == 1)
  1283.         return (m);
  1284.     fprintf(stdout, "No value or value out of range; please try again\n");
  1285. #endif
  1286.     }
  1287.     plexit("Too many tries.");
  1288.     return (0);
  1289. }
  1290.  
  1291. /*----------------------------------------------------------------------*\
  1292.  * plGetFlt()
  1293.  *
  1294.  * Prompts human to input a float in response to given message.
  1295. \*----------------------------------------------------------------------*/
  1296.  
  1297. PLFLT
  1298. plGetFlt(char *s)
  1299. {
  1300.     PLFLT m;
  1301.     int i = 0;
  1302.     char line[256];
  1303.  
  1304.     while (i++ < 10) {
  1305.     fprintf(stdout, s);
  1306.     fgets(line, sizeof(line), stdin);
  1307. #ifdef MSDOS
  1308.     m = atof(line);
  1309.     return (m);
  1310. #else
  1311.     if (sscanf(line, "%f", &m) == 1)
  1312.         return (m);
  1313.     fprintf(stdout, "No value or value out of range; please try again\n");
  1314. #endif
  1315.     }
  1316.     plexit("Too many tries.");
  1317.     return (0.);
  1318. }
  1319.